﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataInterpolator.Model
{
   public class InputFile
   {
      public InputFile(string filename)
      {
         Parsed = false;
         Filename = filename;

         IndexedXValues = new List<double>();
         IndexedYValues = new List<double>();
      }

      public int RowCount { get; set; }

      public bool Parsed { get; private set; }

      public string Filename { get; private set; }

      public string SelectedColumn { get; private set; }
      public string[] ColumnNames { get; set; }
      public double[][] ColumnData { get; set; }

      public double[] RowData { get; set; }
      public List<double> IndexedXValues { get; private set; }

      public List<double> IndexedYValues { get; private set; }

      private int GetColumnIndex(string columnName)
      {
         for (int i = 0; i < ColumnNames.Length; i++)
         {
            if (string.Equals(columnName, ColumnNames[i], StringComparison.OrdinalIgnoreCase))
            {
               return i;
            }
         }

         return -1;
      }

      public void SetSelectedColumn(string columnName)
      {
         if (GetColumnIndex(columnName) != -1)
         {
            SelectedColumn = columnName;
         }
      }

      public void UpdateIndexedData(double indexStart, double indexSpacing)
      {
         int yIndex = GetColumnIndex(SelectedColumn);

         if (yIndex == -1)
            return;

         IndexedXValues.Clear();
         IndexedYValues.Clear();

         for (int i = 0; i < RowCount; i++)
         {
            if (double.IsNaN(ColumnData[yIndex][i]))
               continue;

            IndexedXValues.Add((RowData[i] - indexStart) / indexSpacing);
            IndexedYValues.Add(ColumnData[yIndex][i]);
         }
      }

      private string[] SeparateLine(string line)
      {
         //The first column is 10, the remainder are 15 characters wide
         if (line.Length < 10)
            return null;

         int prev = 0;

         List<string> separated = new List<string>();

         for (int i = 10; i <= line.Length; i += 15)
         {
            separated.Add(line.Substring(prev, i - prev).Trim());

            prev = i;
         }

         return separated.ToArray();
      }

      void FindLeadTrailZeros(List<double> data, out int firstValid, out int lastValid)
      {
         firstValid = data.FindIndex((val) =>
         {
            return val != 0.0 && !double.IsNaN(val);
         });

         lastValid = data.FindLastIndex((val) =>
         {
            return val != 0.0 && !double.IsNaN(val);
         });
      }

      public void ParseFile()
      {
         //Only parse once per filename
         if (Parsed)
            return;

         if (!File.Exists(Filename))
            throw new FileNotFoundException("Could not find file: " + Filename);

         string[] lines = File.ReadAllLines(Filename);

         if (lines.Length < 12)
            throw new FileLoadException("Error loading file. Invalid format.", Filename);

         List<string> headers = new List<string>(SeparateLine(lines[6]));



         //Break up the data into doubles
         List<List<double>> colData = new List<List<double>>();

         for (int i = 0; i < headers.Count; i++)
         {
            //Add one list per column
            colData.Add(new List<double>());
         }

         for (int i = 10; i < lines.Length; i++)
         {
            string[] splitData = SeparateLine(lines[i]);

            if (splitData.Length != headers.Count)
               continue;

            for (int colIdx = 0; colIdx < splitData.Length; colIdx++)
            {
               double value = double.NaN;

               //Check for special values that indicate null values
               Double.TryParse(splitData[colIdx], out value);

               if (value == -9999.25)
               {
                  value = double.NaN;
               }

               colData[colIdx].Add(value);
            }
         }

         List<double> rowData = null;

         //find the independent column
         for (int i = headers.Count - 1; i >= 0; i--)
         {
            if (string.Equals("DEPTH", headers[i], StringComparison.OrdinalIgnoreCase))
            {
               rowData = colData[i];

               for (int j = 0; j < rowData.Count; j++)
               {
                  rowData[j] *= -1.0;
               }

               colData.RemoveAt(i);
               headers.RemoveAt(i);
            }
            if (string.Equals("TIME", headers[i], StringComparison.OrdinalIgnoreCase))
            {
               colData.RemoveAt(i);
               headers.RemoveAt(i);
            }
         }

         int firstValid = 0;
         int lastValid = 0;

         FindLeadTrailZeros(rowData, out firstValid, out lastValid);

         rowData.RemoveRange(lastValid + 1, rowData.Count - (lastValid + 1));
         rowData.RemoveRange(0, firstValid);

         for (int j = 0; j < colData.Count; j++)
         {
            colData[j].RemoveRange(lastValid + 1, colData[j].Count - (lastValid + 1));
            colData[j].RemoveRange(0, firstValid);
         }

         RowData = rowData.ToArray();
         RowCount = rowData.Count;
         ColumnData = new double[colData.Count][];

         for (int i = 0; i < colData.Count; i++)
         {
            //Now find leading and trailing zeros and set to NaN
            FindLeadTrailZeros(colData[i], out firstValid, out lastValid);

            for (int j = 0; j < firstValid; j++)
            {
               colData[i][j] = double.NaN;
            }

            for (int j = lastValid + 1; j < colData[i].Count; j++)
            {
               colData[i][j] = double.NaN;
            }

            ColumnData[i] = colData[i].ToArray();
         }

         ColumnNames = headers.ToArray();

         //Finally, try to set the default column name
         SelectedColumn = ColumnNames[0];

         Parsed = true;
      }
   }
}
